package oglTest;

import java.awt.Component;
import java.awt.Frame;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.opengl.GL;
//import javax.media.opengl.GL2;
//import javax.media.opengl.GL2ES1;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLCanvas;
//import javax.media.opengl.fixedfunc.GLLightingFunc;
//import javax.media.opengl.fixedfunc.GLMatrixFunc;
import javax.media.opengl.glu.GLU;

//import com.jogamp.opengl.util.Animator;
import com.sun.opengl.util.Animator;
import com.sun.opengl.util.j2d.TextRenderer;
import gov.nasa.worldwind.awt.WorldWindowGLCanvas;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.render.Polygon;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import settings.Config;
import visualization.GroundData;
import visualization.Ship;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureData;
import com.sun.opengl.util.texture.TextureIO;
import java.awt.Font;
import java.io.FileInputStream;
import java.io.InputStream;

public class oglTest implements GLEventListener, KeyListener, MouseMotionListener, MouseListener
{
    public final float pozycjax = -47.69f;
    
    public float akto = 0, aktwx = 0, aktwy = 0, aktwz = 0;
    public float obx = pozycjax, oby = -7, obz = 20.37f;                // pozycja obserwatora
    public float kato = 2.23f, katov = -0.2f;             // kat patrzenia obserwatora
    public int przesx = 3, przesy = 1, przesz = 3;
    public float odstep = 0.5f;
    int starex, starey;
    int jestcontrol;
    int lpm = 0;
    boolean animacja = false;
    boolean zasonarem = true;
    boolean czywc = false;
    boolean czypomoc = false;
    public static boolean update = true;
    static JFrame sframe = null;
    static FSterowanie ster = null;
    
    public int kierunek = 2;
    public Timer timer;
    public Zadanie zadanie;
    
    TextRenderer renderer;
    int fontsize = 17;
    private Texture wTexture;
    Ship ship = null;
    GroundData gData = null;
    WorldWindowGLCanvas wwd;
    float[] LightAmbient =
    {
        0.2f, 0.2f, 0.2f, 0.2f
    };
    float[] LightDiffuse =
    {
        1.0f, 1.0f, 1.0f, 1.0f
    };
    float[] LightPosition =
    {
        5.0f, 6.0f, 2.0f, 0.0f
    };
    float rotateT = 0.0f;
    AllDraw sonar;

    public oglTest(JFrame sframe)
    {
        this.sframe = sframe;
    }

    public oglTest(JFrame sframe, Ship ship, GroundData gData, WorldWindowGLCanvas wwd)
    {
        this.sframe = sframe;
        this.ship = ship;
        this.gData = gData;
        this.wwd = wwd;
    }

    public Vector getEye()
    {
        return new Vector(obx - aktwx, oby + aktwy, obz + aktwz);
    }

    public Vector getTarget()
    {
        return new Vector(obx + (float) Math.sin(kato) * 35 - aktwx, oby + (float) Math.sin(katov) * 20 + aktwy, obz + (float) Math.cos(kato) * 35 + aktwz);
    }

    public Vector getUp()
    {
        return new Vector(0, 1, 0);
    }

    public void moveForward()
    {
        obz = obz + przesz * (float) Math.cos(kato);
        obx = obx + przesz * (float) Math.sin(kato);
    }

    public void moveBackward()
    {
        obz = obz - przesz * (float) Math.cos(kato);
        obx = obx - przesz * (float) Math.sin(kato);
    }

    public void moveLeft()
    {
        obx = obx + przesx * (float) Math.cos(kato);
        obz = obz - przesx * (float) Math.sin(kato);
    }

    public void moveRight()
    {
        obx = obx - przesx * (float) Math.cos(kato);
        obz = obz + przesx * (float) Math.sin(kato);
    }

    public void moveUp()
    {
        oby += przesy;
    }

    public void moveDown()
    {
        oby -= przesy;
    }

    public void patrzX(float f)
    {
        kato = (float) (kato + f);
    }

    public void patrzY(float f)
    {
        katov = (float) (katov + f);
        if (katov > 1.5)
        {
            katov = (float) 1.5;
        }
        if (katov < -1.5)
        {
            katov = (float) -1.5;
        }
    }

    static GLU glu = new GLU();
    static GLCanvas canvas = new GLCanvas();
    static Frame frame = new Frame("Sonar animation");
    static Animator animator = new Animator(canvas);

    @Override
    public void display(GLAutoDrawable gLDrawable)
    {
        final GL gl = gLDrawable.getGL();

        // aktualizacja pozycji statku na mapie
        try
        {
            gData.currentPing = sonar.akti / gData.pingSkip;
            //Position shipPos = new Position(gData.positions[0][0].getLatitude(), gData.positions[0][0].getLongitude(), 150);
            Position shipPos = new Position(gData.positions[gData.currentPing][gData.beamsNumber / gData.beamSkip].getLatitude(), gData.positions[gData.currentPing][gData.beamsNumber / gData.beamSkip].getLongitude(), ship.altitude);
            ship.moveTo(shipPos);
            //wwd.repaint();
        }
        catch (Exception e)
        {
        }
        
        //render aniamcji
        if(!czywc){
            gl.glMatrixMode(GL.GL_PROJECTION);
            gl.glLoadIdentity();
            int XSize = frame.getBounds().width, YSize = frame.getBounds().height;
            float h = (float) XSize / (float) YSize;
            glu.gluPerspective(50.0f, h, 1.0, 1000.0);
            gl.glMatrixMode(GL.GL_MODELVIEW);
            gl.glLoadIdentity();
            
            gl.glDisable(GL.GL_TEXTURE_2D);
            gl.glClear(GL.GL_COLOR_BUFFER_BIT);
            gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
            gl.glLoadIdentity();

            glu.gluLookAt(this.getEye().X, this.getEye().Y, this.getEye().Z,
                this.getTarget().X, this.getTarget().Y, this.getTarget().Z,
                this.getUp().X, this.getUp().Y, this.getUp().Z);

            gl.glTranslatef(0.0f, 0.0f, -5.0f);

            sonar.DrawAllLines(gl, glu, animacja, odstep);
        }else{
            int XSize = frame.getBounds().width, YSize = frame.getBounds().height;
            gl.glMatrixMode (GL.GL_PROJECTION);
            gl.glLoadIdentity ();
            gl.glOrtho (0, XSize, YSize, 0, 0, 1);
            gl.glMatrixMode (GL.GL_MODELVIEW);
            gl.glLoadIdentity();
            gl.glClear(GL.GL_COLOR_BUFFER_BIT);
            
            gl.glEnable(GL.GL_TEXTURE_2D);
            
            if(new File(sonar.path+".cache/"+sonar.akti+".png").exists()){
                try {
                    InputStream stream = new FileInputStream(sonar.path+".cache/"+sonar.akti+".png");
                    TextureData data = TextureIO.newTextureData(stream, false, "png");
                    wTexture = TextureIO.newTexture(data);
                }
                catch (IOException exc) {
                    exc.printStackTrace();
                    System.exit(1);
                }
            
                wTexture.enable();
                wTexture.bind();
            
                int pos = (XSize-YSize)/2;
                gl.glBegin(GL.GL_QUADS);
                    gl.glColor3f(2, 2, 2);
                    gl.glTexCoord2f(0, 0);
                    gl.glVertex2f(0, 0);
                    gl.glColor3f(2, 2, 2);
                    gl.glTexCoord2f(0, 1);
                    gl.glVertex2f(0, YSize);
                    gl.glColor3f(2, 2, 2);
                    gl.glTexCoord2f(1, 1);
                    gl.glVertex2f(XSize, YSize);
                    gl.glColor3f(2, 2, 2);
                    gl.glTexCoord2f(1, 0);
                    gl.glVertex2f(XSize, 0);
                gl.glEnd();
            }
        }
        //rysowanie pomocy
        drawText(gl);
        
        update = false;
    }
    
    void drawText(GL gl){
        int XSize = frame.getBounds().width, YSize = frame.getBounds().height;
        gl.glEnable(GL.GL_TEXTURE_2D);
        
        renderer.beginRendering(XSize, YSize);
        renderer.setColor(1.0f, 0.2f, 0.2f, 0.8f);
        if(!czypomoc){
            renderer.draw("[H] : Help", 10, YSize - 20);
        } else {
            int ii = 20;
            renderer.draw("[ ]       : toggle help\n", 10, YSize - ii); ii+=fontsize;
            ii+=fontsize;
            renderer.draw("View:\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[     ]   : change direction\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[       ] : move sideways\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[       ] : move up\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[       ] : move down\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[ ]       : toggle follow mode\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[ ]       : move to sonar's position\n", 10, YSize - ii); ii+=fontsize;
            ii+=fontsize;
            renderer.draw("Animation settings:\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[ ]       : toggle animation\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[  ]      : previous swath\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[  ]      : next swath\n", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[ ]       : toggle water column data", 10, YSize - ii); ii+=fontsize;
            renderer.draw("[ ]       : toggle 2D mode\n", 10, YSize - ii); ii+=fontsize;
            
            renderer.setColor(1.0f, 1.0f, 0.0f, 0.8f);
            ii = 20;
            renderer.draw(" H ", 10, YSize - ii); ii+=fontsize;
            ii+=fontsize;
            ii+=fontsize;
            renderer.draw(" mouse ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" W S A D ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" space+W ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" space+S ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" Z ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" Y ", 10, YSize - ii); ii+=fontsize;
            ii+=fontsize;
            ii+=fontsize;
            renderer.draw(" T ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" <- ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" -> ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" C ", 10, YSize - ii); ii+=fontsize;
            renderer.draw(" Y ", 10, YSize - ii); ii+=fontsize;
        }
        renderer.endRendering();
        
        update = false;
    }
    
    @Override
    public void displayChanged(GLAutoDrawable gLDrawable, boolean modeChanged, boolean deviceChanged)
    {
    }

    @Override
    public void init(GLAutoDrawable gLDrawable)
    {
        renderer = new TextRenderer(new Font("Courier New", Font.BOLD, fontsize));
        GL gl = gLDrawable.getGL();
        gl.glShadeModel(GL.GL_SMOOTH);
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glClearDepth(1.0f);
        gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glDepthFunc(GL.GL_LEQUAL);
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
        ((Component) gLDrawable).addKeyListener(this);
        ((Component) gLDrawable).addMouseListener(this);
        ((Component) gLDrawable).addMouseMotionListener(this);

        try
        {
            if (sonar == null)
            {
                System.out.println("fail");
                sonar = new AllDraw(0, 99, new Config().testFilePath);
            }
        }
        catch (Exception e)
        {
        }

        // okno sterowania
        if (ster != null)
        {
            ster.dispose();
        }
        ster = new FSterowanie(this);
        ster.setAlwaysOnTop(true);
        ster.setVisible(true);
        
        timer = new Timer();
        zadanie = new Zadanie();
        timer.schedule(zadanie, 0, 33);
    }

    public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height)
    {
        GL gl = gLDrawable.getGL();
        if (height <= 0)
        {
            height = 1;
        }
        float h = (float) width / (float) height;
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(50.0f, h, 1.0, 1000.0);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    @Override
    public void keyPressed(KeyEvent e)
    {
        //System.out.println(obx+" "+oby+" "+obz+" "+kato);
        
        if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
        {
            exit();
        }
        if (e.getKeyCode() == KeyEvent.VK_SPACE)
        {
            jestcontrol = 1;
        }
        switch (e.getKeyCode())
        {
            case KeyEvent.VK_W:
                if (jestcontrol == 1)
                {
                    moveUp();
                    break;
                }
                moveForward();
                break;
            case KeyEvent.VK_S:
                if (jestcontrol == 1)
                {
                    moveDown();
                    break;
                }
                moveBackward();
                break;
            case KeyEvent.VK_A:
                moveLeft();
                break;
            case KeyEvent.VK_D:
                moveRight();
                break;
            case KeyEvent.VK_T:
                if (animacja)
                {
                    animacja = false;
                    wwd.repaint();
                }
                else
                {
                    animacja = true;
                    wwd.repaint();
                }
                break;
            case KeyEvent.VK_Y:
                if (czywc)
                {
                    czywc = false;
                    wwd.repaint();
                    //startstop.setText("Start");
                }
                else
                {
                    czywc = true;
                    wwd.repaint();
                    //startstop.setText("Stop");
                }
                break;
            case KeyEvent.VK_LEFT:
                sonar.akti--;
                if (sonar.akti < 0) sonar.akti = 0;
                break;
            case KeyEvent.VK_RIGHT:
                sonar.akti++;               
                if (sonar.akti >= sonar.datagram68.size()) sonar.akti = 0;
                break;
            case KeyEvent.VK_Z:
                if(zasonarem){
                    zasonarem = false;
                } else {
                    obx = pozycjax;      
                    zasonarem = true;
                }
                break;
            case KeyEvent.VK_X:
                obx = pozycjax;               
                break;
             case KeyEvent.VK_C:
                sonar.jestawc = !sonar.jestawc ;               
                break;
             case KeyEvent.VK_H:
                czypomoc = !czypomoc ;               
                break;
        }
        update = true;
    }

    @Override
    public void keyReleased(KeyEvent e)
    {
        if (e.getKeyCode() == KeyEvent.VK_SPACE)
        {
            jestcontrol = 0;
        }
    }

    @Override
    public void keyTyped(KeyEvent e)
    {
    }

    @Override
    public void mousePressed(MouseEvent e)
    {
    }

    @Override
    public void mouseReleased(MouseEvent e)
    {
    }

    @Override
    public void mouseDragged(MouseEvent e)
    {
        int x = e.getX();
        int y = e.getY();
        if (x < starex)
        {
            starex = x;
            patrzX((float) 0.15);
            update = true;
        }
        else if (x > starex)
        {
            starex = x;
            patrzX((float) -0.15);
            update = true;
        }
        if (y < starey)
        {
            starey = y;
            patrzY((float) 0.15);
            update = true;
        }
        else if (y > starey)
        {
            starey = y;
            patrzY((float) -0.15);
            update = true;
        }
    }

    @Override
    public void mouseExited(MouseEvent e)
    {
    }

    @Override
    public void mouseEntered(MouseEvent e)
    {
    }

    @Override
    public void mouseClicked(MouseEvent e)
    {
    }

    @Override
    public void mouseMoved(MouseEvent e)
    {
    }

    public static void close()
    {
        update = false;
        animator.stop();
        frame.dispose();
    }

    public static void exit()
    {
        close();
        System.exit(0);
    }

    public static void main(String[] args)
    {

        oglTest tt = new oglTest(new JFrame("Animation Tools"));
        canvas.addGLEventListener(tt);
        frame.add(canvas);
        frame.setSize(1024, 700);

        frame.addWindowListener(new WindowAdapter()
        {
            public void windowClosing(WindowEvent e)
            {
                exit();
            }
        });
        frame.setVisible(true);
        animator.start();
        canvas.requestFocus();
    }

    public void trun(AllDraw tsonar)
    {
        sonar = tsonar;
        if (sonar == null)
        {
            System.out.println("fail");
        }
        else
        {
            System.out.println(sonar.datagram68.size());
        }

        //oglTest tt = new oglTest();
        canvas.addGLEventListener(this);
        frame.add(canvas);
        frame.setSize(1024, 700);

        frame.addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent e)
            {
                exit();
            }
        });
        frame.setVisible(true);
        animator.start();
        canvas.requestFocus();
    }

    public void dispose(GLAutoDrawable gLDrawable)
    {
        // do nothing
    }

    void nowyCzas(int czas) {
        timer.cancel();
        timer = new Timer();
        zadanie = new Zadanie();
        timer.schedule(zadanie, 0, czas);
    }

    class Vector
    {
        public float X, Y, Z;

        public Vector(float x, float y, float z)
        {
            X = x;
            Y = y;
            Z = z;
        }
    }

    public class Zadanie extends TimerTask
    {
        @Override
        public void run()
        {
            if (animacja)
            {
                sonar.akti += kierunek;
                ster.updateSliderValue();
                if(!zasonarem) {
                    obx-=sonar.skok*kierunek;
                    if(obx<pozycjax-sonar.skok*sonar.zakres)
                        obx = pozycjax;
                }
            }

            if (animacja || update)
            {
                if (!animator.isAnimating())
                {
                    animator.start();
                }
            }
            else
            {
                if (animator.isAnimating())
                {
                    animator.stop();
                }
            }
            if (sonar.akti >= sonar.datagram68.size())
            {
                sonar.akti = 0;
            }
            if (sonar.akti < 0)
            {
                sonar.akti = sonar.datagram68.size();
            }
            //System.out.println(obx+" "+oby+" "+obz+" "+kato+" "+katov);
        }
    }
}
